package com.gitee.wsl.common.ui.symbol.generator

import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Path
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

 fun <D> PathBuilder.Companion.pie(rect: Rect,init: PieGenerator<D>.() -> Unit): PieGenerator<D> = PieGenerator<D>(rect).apply(init)

class PieGenerator<D>(var rect: Rect = Rect.Zero):PathBuilder<D>() {

     var value: (D) -> Float = const(.0f)
     var startAngle: (List<D>) -> Float = const(.0f)
     var endAngle: (List<D>) -> Float = const(tau)
     var padAngle: (List<D>) -> Float = const(.0f)


    /**
     * Use the data to generate a line on the path
     */
     fun buildParams(data: List<D>): Array<ArcParams<D>> {
        val n = data.size
        var sum = .0f
        val index: Array<Int> = Array(n) { 0 }
        val arcs: Array<ArcParams<D>> = Array(n) { ArcParams<D>(.0f, .0f, .0f, null, null, null) }
        val values: Array<Float> = Array(n) { .0f }
        var a0 = startAngle(data)
        val da = min(tau, max(-tau, endAngle(data) - a0))
        val p =  min(abs(da) / n, padAngle(data)) //  min(abs(da) / n, .0)
        val pa = if (da < .0) -p else p

        for (i in 0 until n) {
            index[i] = i
            val v = value(data[i])
            values[i] = v
            if (v > 0) sum += v
        }

        // TODO : sorting
        // Optionally sort the arcs by previously-computed values or by data.
        //if (sortValues != null) index.sort(function(i, j) { return sortValues(arcs[i], arcs[j]); });
        //else if (sort != null) index.sort(function(i, j) { return sort(data[i], data[j]); });

        // Compute the arcs! They are stored in the original data's order.
        val k = if (sum > .0f) ((da - n * pa) / sum) else .0f
        for (i in 0 until n) {
            val j = index[i]
            val v = values[j]
            val a1 = a0 + (if (v > .0f) (v * k) else .0f) + pa
            arcs[j] = ArcParams(a0, a1, p, v,i, data[j])
            a0 = a1
        }

        return arcs
    }

     override fun <C : Path> build(data: List<D>, path: C): C {
         buildParams(data).forEach {
             path.addArc(rect, startAngleDegrees = it.startAngle, sweepAngleDegrees = it.sweepAngle)
         }
         return path
     }
 }

data class ArcParams<T>(
    val startAngle: Float,
    val endAngle: Float,
    val padAngle: Float?,
    val value: Float?,
    val index: Int?,
    val data: T?
){
    val sweepAngle:Float get() = endAngle - startAngle + (padAngle?:0f)
}